/***************************************************************\

    ^^^^^^^^  ^^^^^^^^  ^^^^^^^^  ^^^^^^^^
    ^^    ^^  ^^    ^^     ^^     ^^    ^^
    ^^        ^^^^^^^^     ^^     ^^^^^^^^
    ^^   ^^^  ^^    ^^     ^^     ^^    ^^
    ^^    ^^  ^^    ^^     ^^     ^^    ^^
    ^^^^^^^^  ^^    ^^  ^^^^^^^^  ^^    ^^

    sample code from the book...
    Real Time 3D Terrain Engines Using C++ and DirectX

    by Greg Snook
    greg@mightystudios.com

\***************************************************************/

#ifndef __INKLUDE_C_TIMER_H__
#define __INKLUDE_C_TIMER_H__

#include <assert.h>
#include <Inklude/Inklude.h>
#include <Inklude/ikCString.h>


namespace Inklude
{

/*!
* @brief The class measurs the time.
* @author Greg Snook, Bitnara Lee, Seokhwan Kim
* @remark This class is based on the code from GAIA engine.
*         Greg Snook created this code at first.
*         After then, it is modified by Bitnara Lee (hlstyle79 at gmail dot com )
*         and customized by Seokhwan Kim.
*/

class INKLUDE_CLASS_EXPORT ikCTimer
{
public:
	enum TIMER_STATE { TIMER_STOP = 0, TIMER_START, TIMER_PAUSE};

private:
	float s_invSecondsFrequency;
	float s_invMillisecondsFrequency;

public:
    ikCTimer(void);
	~ikCTimer(void);

public:
	void Start(void);	
	void Stop(void);	
	void Pause(void);	
	void Resume(void);	
	float ElapsedSeconds(void);
	float ElapsedMilliseconds(void);
    unsigned __int64 ElapsedCount(void);
    void GetCurrentTimeInString(Inklude::ikCString& StringTime);
    void GetCurrentTimeInNumber(unsigned int& Year, unsigned int& Month, unsigned int& Day, unsigned int& Hour, unsigned int& Minute, unsigned int& Second, unsigned int& Millisecond);

private:
	void setupTimerFrequency(void);
	unsigned __int64 samplePerformanceCounter(void);

protected:
	unsigned __int64 m_startClock;
	unsigned __int64 m_currentClock;
	unsigned __int64 m_clockDelta;
	unsigned __int64 m_elapsedCount;
	TIMER_STATE		m_state;
};

inline void ikCTimer::Start(void)
{
	m_startClock = samplePerformanceCounter();

	m_state = TIMER_START;
	m_elapsedCount = 0;
}


inline void ikCTimer::Stop(void)	
{
	m_elapsedCount = ElapsedCount();
	m_state = TIMER_STOP;
}


inline void ikCTimer::Pause(void)	
{
	if (m_state == TIMER_START)
	{
		m_state = TIMER_PAUSE;
		m_elapsedCount = ElapsedCount();
	}
}


inline void ikCTimer::Resume(void)	// resume the timer from when is was stopped
{
	if (m_state == TIMER_PAUSE)
	{
		// get the current time
		m_startClock = samplePerformanceCounter();

		// roll the start time back by our previous delta
		m_startClock -= m_clockDelta;

		m_elapsedCount = 0;
		m_state = TIMER_START;
	}
}

inline unsigned __int64 ikCTimer::ElapsedCount(void)
{
	if (m_state != TIMER_START)
	{
		return m_elapsedCount;
	}
	else
	{
		m_currentClock = samplePerformanceCounter();
		m_clockDelta = m_currentClock - m_startClock;

		return(m_clockDelta);
	}
}

inline float ikCTimer::ElapsedSeconds(void)
{
	return ((float)ElapsedCount()) * s_invSecondsFrequency;
}

inline float ikCTimer::ElapsedMilliseconds(void)
{
	return ((float)ElapsedCount()) * s_invMillisecondsFrequency;
}

}		// namespace TILE_UTIL

#endif	// __INKLUDE_C_TIMER_H__
